package com.example.lock.service;

import com.alibaba.fastjson2.JSON;
import com.example.lock.annotation.ConcurrentLock;
import com.example.lock.constant.RedisKeys;
import com.example.lock.mapper.StudentMapper;
import com.example.lock.model.Hobby;
import com.example.lock.model.Student;
import com.example.lock.util.IDGenerator;
import com.example.lock.util.RandomUtils;
import com.example.lock.util.RedissonLockUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * <p>Description: </p>
 *
 * @author zg
 * @version v1.0.0
 * @since 2024/8/19
 **/
@Slf4j
@RequiredArgsConstructor
@Service
public class StudentService {

    private final StudentMapper studentMapper;
    private final IDGenerator idGenerator;
    private final RedissonLockUtils redissonLockUtils;

    public List<Student> list() {

        return studentMapper.selectAll();
    }

    public void add(Student stu) {
        long sid = idGenerator.generateSID();
        stu.setSid(sid);
        studentMapper.insertSelective(stu);
    }

    public void delete(Long sid) {
        studentMapper.deleteByPrimaryKey(sid);
    }

    //@ParamsTrace(name = "根据sid查询")
    @ConcurrentLock(key = RedisKeys.MODIFY_SALE_DETAIL_DISTRIBUTION, values = {"#sid"}, isFairLock = true)
    public Student getBySid(Long sid) {

        return studentMapper.selectByPrimaryKey(sid);
    }

    @ConcurrentLock(key = RedisKeys.MODIFY_SALE_DETAIL_DISTRIBUTION, values = {"#stu.sid", "#stu.name"}, isFairLock = true)
    public void updateBySid(Student stu) {
        studentMapper.updateByPrimaryKeySelective(stu);
    }

    //@ConcurrentLock(key = RedisKeys.MODIFY_SALE_DETAIL_DISTRIBUTION, values = {"#stu.sid", "#hobby.hobbyName"}, isFairLock = true)
    @ConcurrentLock(key = RedisKeys.MODIFY_SALE_DETAIL_DISTRIBUTION, values = {"#hobby.hobbyName"}, isFairLock = true)
    public void updateBySidAndHobby(Student stu, Hobby hobby) {
        log.warn("updateBySidAndHobby..., stu={},hobby={}", JSON.toJSONString(stu), JSON.toJSONString(hobby));
        studentMapper.updateByPrimaryKeySelective(stu);
    }

    public void increaseScoreSynchronized(long sid, int increaseScore) {
        String lockKey = null;
        RLock lock = null;
        try {
            lockKey = "lock:increaseScore:" + sid;
            lock = redissonLockUtils.getLock(lockKey);
            if(redissonLockUtils.tryLock(lock, 30)){
                increaseScore(sid, increaseScore);
            }else{
                log.warn("获取锁失败。lockKey={}", lockKey);
            }
        } catch (Exception e) {
            //e.printStackTrace();
            log.error("执行异常。sid={},increaseScore={},lockKey={}", sid, increaseScore, lockKey, e);
        } finally {
            redissonLockUtils.unlock(lock);
        }
    }

    public void increaseScoreSynchronized1(long sid, int increaseScore) {
        String lockKey = null;
        RLock lock = null;
        try {
            lockKey = "lock:increaseScore:" + sid;
            lock = redissonLockUtils.tryLockAndGet(lockKey, 30, 30);
            increaseScore(sid, increaseScore);
        } catch (Exception e) {
            //e.printStackTrace();
            log.error("执行异常。sid={},increaseScore={},lockKey={}", sid, increaseScore, lockKey, e);
        } finally {
            redissonLockUtils.unlock(lock);
        }
    }

    public void increaseScore(long sid, int increaseScore) {
        long time = System.currentTimeMillis();
        String threadName = Thread.currentThread().getName();
        log.info("[{}]start, sid={},increaseScore={}", threadName, sid, increaseScore);
        int randomWait = 0;
        try {
            randomWait = RandomUtils.getRandomInt(2, 5);
            Thread.sleep(randomWait * 1000);
        } catch (InterruptedException e) {
            //e.printStackTrace();
            log.error("[{}]sid={},increaseScore={}", threadName, sid, increaseScore, e);
        }
        Student student = studentMapper.selectByPrimaryKey(sid);
        int score = student.getScore() + increaseScore;
        Student stu = Student.builder().sid(sid).score(score).build();
        studentMapper.updateByPrimaryKeySelective(stu);
        log.info("[{}]end use {} seconds. sid={},increaseScore={},randomWait={}", threadName, (System.currentTimeMillis() - time)/1000, sid, increaseScore, randomWait);
    }

    @ConcurrentLock(values = {"#sid"}, isFairLock = true, waitingTime = 10)
    public void increaseScoreWithLockAnno(long sid, int increaseScore) {
        try {
            increaseScore(sid, increaseScore);
        } catch (Exception e) {
            log.error("StudentService.increaseScoreWithLockAnno异常，sid={},increaseScore={}", sid, increaseScore, e);
        }
    }

}
